﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;
using Firefly.Controls.Extentions;

namespace Firefly.Controls {
    public class Terminal : RichTextBox {
        // Parser for ANSI and filters.
        public TerminalParser Parser { get; private set; }
        // Delegate callbacks for threadsafe operations
        private delegate void AppendTextCallback(TextFragment text);
        private delegate void ScrollToCaretCallback();

        public Terminal() {
            this.Parser = new TerminalParser();
            this.outputBuffer = new Queue<TextFragment>();
            this.Dock = DockStyle.Fill;
            this.ReadOnly = true;
            // Program wide updates to update the buffer.
            Program.UpdateEvent += new EventHandler(delegate(object o, EventArgs e) {
                ProcessBuffer();
            });
            // Remember to close the buffer.
            Program.OnApplicationQuit += new EventHandler(delegate(object o, EventArgs e) {
                this.Dispose();
            });
        }

        protected override void OnResize(EventArgs e) {
            ScrollToCaret();
            base.OnResize(e);
        }

        protected void ProcessBuffer() {
            while (outputBuffer.Count > 0) {
                // Threadsafe callback to Windows Forms.
                this.Invoke(new AppendTextCallback(AppendText), new object[] { outputBuffer.Dequeue() });

                if (!mBlockScroll && outputBuffer.Count == 0)
                    this.Invoke(new ScrollToCaretCallback(ScrollToCaret));
            }
        }

        public new void AppendText(string s) {
            TextFragment[] text = Parser.Parse(s);
            foreach (TextFragment tf in text) {
                outputBuffer.Enqueue(tf);
            }
        }
  
        public void AppendText(TextFragment text) {
            FontStyle fontStyle;
            if (text.Text != null) {
                if (text.Ansi.Underline) {
                    fontStyle = FontStyle.Underline;
                } else if(text.Ansi.Blink) {
                    fontStyle = FontStyle.Bold;
                } else {
                    fontStyle = FontStyle.Regular;
                }
                // Caret to bottom.
                this.SelectionStart = this.Text.Length;
                // Set font properties.
                this.SelectionFont = new System.Drawing.Font(Font.FontFamily, Font.SizeInPoints,
                    fontStyle, GraphicsUnit.Point, ((byte)(0)));
                this.SelectionColor = text.Ansi.PrimaryColor;
                this.SelectionBackColor = text.Ansi.SecondaryColor;
                this.SelectedText = text.Text;
            }
            
        }

        private Queue<TextFragment> outputBuffer;
        private bool mBlockScroll;
        
    }
}
